package cn.takujo.takujoframework.mybatis.sqlhelper.insert;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import cn.takujo.takujoframework.mybatis.sqlhelper.base.Form;
import cn.takujo.takujoframework.mybatis.sqlhelper.base.Rule;
import lombok.Getter;

/**
 * 插入规则，需要继承或匿名实现
 * 
 * @author wzx
 *
 * @param <T>
 *            Form的实现类
 */
public abstract class InsertRule<T extends Form> implements Rule {

	@Getter
	private String table;

	private T form;
	private Class<? extends Form> cla;

	/**
	 * @param table
	 *            表名
	 * @param form
	 *            Form实现类
	 */
	public InsertRule(String table, T form) {
		this.table = table;
		this.form = form;
		this.cla = form.getClass();
	}

	/**
	 * @return 基础sql
	 */
	public String base() {
		return "INSERT INTO " + table + " ";
	}

	/**
	 * 重要！ 用来生成插入条件, 重写时return的最外层一定是values方法 默认是全部插入
	 * 
	 * @return 条件sql
	 */
	@Override
	public String generate() {
		return lengthNotEqualZero(lengthEqualZero());
	}

	@Override
	public String commit() {
		return base() + generate();
	}

	/**
	 * 要插入的单个值
	 * 
	 * @param column
	 *            数据库列名
	 * @param property
	 *            映射java对象属性名
	 * @return 一个值条件
	 */
	public static String[] value(String column, String property) {
		String[] s = new String[2];
		s[0] = column;
		s[1] = "#{" + property + "}";
		return s;
	}

	/**
	 * 要插入的值集合
	 * 
	 * @param value
	 *            条件必须是以下方法的返回值，且任意数量个（可以为零）： value
	 * @return 多个值条件
	 */
	public String values(String[]... value) {
		int length = value.length;
		if (length == 0) {
			return lengthNotEqualZero(lengthEqualZero());
		} else {
			return lengthNotEqualZero(value);
		}
	}

	private String lengthNotEqualZero(String[][] value) {
		int length = value.length;
		StringBuffer l = new StringBuffer("(");
		StringBuffer v = new StringBuffer("VALUES(");
		for (int i = 0; i < length; i++) {
			String[] s = value[i];
			String s1 = s[0];
			String s2 = s[1];
			if (s1.equals("id") || s2.equals("id")) {
				continue;
			}
			Object o = fieldValueIsExist(s2);
			if (o != null) {
				l.append(s1 + ",");
				v.append(s2 + ",");
			}
		}
		int lastIndexOf = l.lastIndexOf(",");
		int lastIndexOf2 = v.lastIndexOf(",");
		if (lastIndexOf != -1) {
			l.deleteCharAt(lastIndexOf);
		}
		if (lastIndexOf2 != -1) {
			v.deleteCharAt(lastIndexOf2);
		}
		l.append(")");
		v.append(")");
		return l.toString() + " " + v.toString();
	}

	private String[][] lengthEqualZero() {
		Class<? extends Form> cla = form.getClass();
		List<String[]> p = new ArrayList<>();
		Field[] declaredFields = cla.getDeclaredFields();
		for (Field field : declaredFields) {
			String name = field.getName();
			int modifiers = field.getModifiers();
			if (!isSerializableField(modifiers) && !name.equals("id")) {
				String[] ss = new String[2];
				ss[1] = "#{" + name + "}";
				char[] array = name.toCharArray();
				StringBuffer sb = new StringBuffer();
				for (char c : array) {
					if (Character.isUpperCase(c)) {
						sb.append('_');
						sb.append(Character.toLowerCase(c));
					} else {
						sb.append(c);
					}
				}
				ss[0] = sb.toString();
				p.add(ss);
			}
		}
		String[][] ss = new String[p.size()][];
		p.toArray(ss);
		return ss;
	}

	@Override
	public Map<String, Object> toMap() {
		Class<? extends Form> cla = form.getClass();
		Map<String, Object> map = new HashMap<>();
		map.put("myRule", this);
		Field[] declaredFields = cla.getDeclaredFields();
		for (Field field : declaredFields) {
			String name = field.getName();
			int modifiers = field.getModifiers();
			if (!isSerializableField(modifiers) && !name.equals("id")) {
				Object o = fieldGetMethodInvoke(name);
				if (o != null) {
					map.put(name, o);
				}
			}
		}
		return map;
	}

	/**
	 * 判断是否为序列化字段
	 * 
	 * @param modifiers
	 * @return true：是 false：否
	 */
	private boolean isSerializableField(int modifiers) {
		if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * 调用某个字段的get方法
	 * 
	 * @param field
	 *            字段名
	 * @return 调用结果为空则返回null
	 */
	private Object fieldGetMethodInvoke(String field) {
		try {
			Method method = cla.getMethod("get" + field.substring(0, 1).toUpperCase() + field.substring(1));
			return method.invoke(form);
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * form中字段值是否存在
	 * 
	 * @return 如果有则返回值，没有则返回null
	 */
	private Object fieldValueIsExist(String field) {
		try {
			int indexOf = field.indexOf("{");
			int lastIndexOf = field.lastIndexOf("}");
			return fieldGetMethodInvoke(field.substring(indexOf + 1, lastIndexOf));
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

}
